#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     __init__.py
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/7/8
-------------------------------------------------
   修改描述-2021/7/8:
-------------------------------------------------
"""
from dataclasses import dataclass


@dataclass
class Base:
    pass
    # 选择表的名称
    select_table = ''
    __where__ = []
    #  # 检索的字段
    __select_fields__ = []
    __sql__ = None
    __lock__ = None  # lock
    __groupby__ = []  # 排序字段
    __orderby__ = []  # 排序字段
    __join__ = []  # leftjoin
    __join_on_exp__ = []  # JOIN表达式的处理
    # 查询全局的总数QUA
    __count__ = []
    # PostgreSQL returning查询返回
    __returning__ = []

    __offset__ = 0
    __limit__ = 0
    __ispaginate_by__ = False

    # 常见的一些表达式关键词
    operators = [
        '=', '<', '>', '<=', '>=', '<>', '!=',
        'like', 'like binary', 'not like', 'between', 'not between',
        '&', '|', '^', '<<', '>>',
        'rlike', 'regexp', 'not regexp',
        '~', '~*', '!~', '!~*', 'similar to',
        'not similar to', 'not ilike', '~~*', '!~~*', 'in', 'not in'
    ]

    # 设置要查询的表名称
    def tablle(self, select_table):
        self.select_table = select_table
        # 重置设置相关信息
        self.__reset__()
        return self

    def __reset__(self):
        # 重置所有的表达式
        self.__where__.clear()
        self.__select_fields__.clear()
        self.__groupby__.clear()  # 排序字段
        self.__orderby__.clear()  # 排序字段
        self.__join__.clear()  # oin
        self.__join_on_exp__.clear()  # join
        self.__sql__ = None
        self.__returning__.clear()
        # 限制数
        self.__limit__ = 0
        # 偏移量
        self.__offset__ = 0
        # 乐观锁
        self.__lock__ = None

        __ispaginate_by__ = False

    def _format_columns(self, columns):
        return list(map(lambda index: index, columns))

    def format_column(self, columns=None):
        return '`{}`'.format(columns)

    def format_string(self, columns):
        return "'{}'".format(columns)

    def _compile_dict(self, data):
        return ['{}={}'.format(index, self.format_string(value)) for index, value in data.items()]

    def _compile_lock(self):
        return '' if not self.__lock__ else self.__lock__

    # 乐观锁
    def lock_by_for_update(self):
        self.__lock__ = ' for update'
        return self

    def sql(self):
        return self.__sql__

    def list_to_str(self, data):
        if data and isinstance(data, list):
            # 把列表转为字符串形式
            return '({})'.format(data[0]) if len(data) == 1 else tuple(data).__str__()
        if data and isinstance(data, tuple):
            return data.__str__()
        else:
            raise Exception('参数异常错误！')

    def list_to_str_no_format(self, data):
        '''
        列表转化为字符串格式
        :param data:
        :return:
        '''
        if data and isinstance(data, list):
            return '{}'.format(data[0]) if len(data) == 1 else tuple(data).__str__()
        if data and isinstance(data, tuple):
            return data.__str__()
        else:
            raise Exception('参数异常错误！')

    def _compile_where(self):
        '''
        开始组合为表达式类型
        :return:
        '''
        # 如果存在表达式值的话
        if len(self.__where__) > 0:
            sqlstr = []
            # 遍历所有的表达式的元素
            for index in self.__where__:
                # 如果表达式里面是一个字典类型的话
                if isinstance(index, dict):
                    # 使用and的符号进行串联起来
                    sqlstr.append(' and '.join(self._compile_dict(index)))
                # 如果是元组类型的话
                elif isinstance(index, tuple):
                    sqlstr.append(self._compile_tuple(index))
                elif isinstance(index, str):
                    sqlstr.append(index)
            return ' where {}'.format(' and '.join(sqlstr))
        return ''

    def _compile_groupby(self):
        # 如果存在分组信息则添加具体的分组字段信息
        return '' if len(self.__groupby__) == 0 else ' group by ' + ','.join(self.__groupby__)

    def _compile_orderby(self):
        # 串联排序字段
        return '' if len(self.__orderby__) == 0 else ' order by ' + ','.join(self.__orderby__)

    def offset(self, number: int):

        if self.__limit__ < 0:
            raise Exception('Limit 数不能小于等于0')

        if not isinstance(number, int):
            raise Exception('offset 必须是整型类型！')

        if number < 0:
            raise Exception('offset 限制数不能小于0')

        self.__offset__ = int(number)
        return self

    def limit(self, number: int):
        if not isinstance(number, int):
            raise Exception('offset 必须是整型类型！')
        if number < 0:
            raise Exception('Limit 限制数不能小于0')
        self.__limit__ = int(number)
        return self

    def paginate(self, page_no: int, page_size: int):
        self.__ispaginate_by__ = True
        self.limit(page_size)
        self.offset((page_no - 1) * page_size)
        return self

    def _compile_limit_offset(self):
        pass
        # 不调用分页的场景情况下
        if not self.__ispaginate_by__:
            __offset__sql = '' if not self.__offset__ else ' offset {}'.format(self.__offset__)
        else:
            # 调用了分页函数场景下
            __offset__sql = ' offset {}'.format(self.__offset__)

        return '' if not self.__limit__ else ' limit {}{}'.format(self.__limit__, __offset__sql)

    # 左连表的查询
    def _compile_leftjoin(self):
        if self.__join__:
            return ' ' + ' '.join([v for v in self.__join__])
        return ''

    def _compile_tuple(self, data):
        # 对in类的 where条件的做特殊的进行处理
        if data[1] in ['in', 'not in']:
            # data[2]的列表类型转为---把列表转为字符串
            return '{} {} {}'.format(data[0], data[1], self.list_to_str(data[2]))
        # 对between的表达式进行特殊的出来
        elif data[1] in ['between', 'not between']:
            # 如果最后的一个参数 存在两个的情况下
            if not (len(data) == 3 and len(data[2]) == 2):
                raise Exception('between表达式错误，需要有三个参数，且最后的一个参数值存在两个值')
            return '{} {} {} and {}'.format(data[0], data[1], self.format_string(data[2][0]), self.format_string(data[2][1]))

        return '{} {} {}'.format(data[0], data[1], self.format_string(data[2]))

    def groupby(self, *args):
        # 批量转换进行列表转
        self.__groupby__ = self._format_columns(list(args))
        return self

    def returning(self, column):
        # 批量转换进行列表转
        if isinstance(column, list):
            self.__returning__ = column
        else:
            self.__returning__.clear()
            self.__returning__.append(column)
        return self

    def orderby(self, column, direction='asc'):
        if direction.lower() == 'asc':
            self.__orderby__.append('{} {}'.format(column, direction))
        else:
            self.__orderby__.append('{} {}'.format(column, 'desc'))
        return self

        # 左连表的查询

    def _compile_returning(self):
        if self.__returning__:
            return 'returning {}'.format(','.join([v for v in self.__returning__]))
        return ''

    def where(self, *args):
        length = args.__len__()
        # 如果传入的查询条件是一个字典类型的，那么就转化为==
        if length == 1 and isinstance(args[0], dict):
            self.__where__.append(args[0])
        # 如果传入的是多个参数那么应该是一个元组类型的
        elif length == 2:
            self.__where__.append({args[0]: args[1]})
        # 如果传入的是一个表达式类型的，就三个的参数
        # 处理判断第二个的参数是否再对应的表达式
        elif length == 3:
            if args[1] in self.operators:
                # 如果是等号的类型
                if args[1] == '=':
                    self.__where__.append({args[0]: args[2]})
                else:
                    # 如果是其他的表达式
                    self.__where__.append((args[0], args[1], args[2]))
            else:
                raise Exception('表达式不在预定义范围内: "{}"'.format(args[1]))
        elif length == 1 and isinstance(args[0], str):
            self.__where__.append(args[0])
        else:
            raise Exception('错误的参数表达式类型')
        return self

    def join_on_exp(self, *args):

        # __join_on_exp__ 串联起来的的格式是使用 三个元祖对象进行串联
        length = args[0].__len__()
        if isinstance(args[0], set):
            raise Exception('__join_on_exp__表达式不知此set类型传入: ')
        elif isinstance(args[0], list):
            # 多条件的类型的串联
            for item in args[0]:
                self.__join_on_exp__.append(item)
            pass
        elif isinstance(args[0], dict):
            for key, value in args[0].items():
                self.__join_on_exp__.append((key, '=', value))
        # 如果传入的查询条件是一个字典类型的，那么就转化为==
        elif length == 1 and isinstance(args[0][0], str):
            # 需要组成三个对象的元祖类型
            self.__join_on_exp__.append((args[0][0], '', ''))
        # 如果传入的是多个参数那么应该是一个元组类型的
        elif length == 1 and isinstance(args[0][0], dict):
            # 多个字典类型的=号的串联
            for key, value in args[0][0].items():
                self.__join_on_exp__.append((key, '=', value))
        # 如果传入的是多个参数那么应该是一个元组类型的
        elif length == 2:
            # 如果里面包含有占位符的标记的话，可以串联起两个的表达式类型
            if '?' in args[0][0]:
                # 需要组成三个对象的元祖类型
                self.__join_on_exp__.append(("{}".format(args[0][0].replace('?', args[0][1])), '', ''))
            else:
                # 没有任何的占位符的默认是= 串联起来
                self.__join_on_exp__.append((args[0][0], '=', args[0][1]))
        # 如果传入的是一个表达式类型的，就三个的参数
        # 处理判断第二个的参数是否再对应的表达式
        elif length == 3:
            if args[0][1] in self.operators:
                # 如果是等号的类型
                if args[0][1] == '=':
                    self.__join_on_exp__.append((args[0][0], '=', args[0][2]))
                else:
                    # 如果是其他的表达式
                    self.__join_on_exp__.append((args[0][0], args[0][1], args[0][2]))
            else:
                raise Exception('__join_on_exp__表达式不在预定义范围内: "{}"'.format(args[0][1]))
        else:
            raise Exception('__join_on_exp__错误的参数表达式类型')
        return self

    def _compile_on(self):

        # if not self.__join_on_exp__:
        #     raise Exception('连表查询缺少__join_on_exp__参数表达式错误！')
        sqlstr = ['{} {} {}'.format(index[0], index[1], index[2]) for index in self.__join_on_exp__]

        return ' and '.join(sqlstr)

    def leftjoin_str(self, join_tablename, on: str):
        # if not  self.__join_on_exp__:
        #     raise Exception('__join_on_exp__缺少必要的JOIN ON表达式！')
        # ON表示的多个条件的处理
        self.__join__.append('left join {} on {}'.format(join_tablename, on))

        return self

    def innerjoin_tuple(self, join_tablename, on):
        self.join_on_exp(on)
        if not self.__join_on_exp__:
            raise Exception('连表查询缺少__join_on_exp__参数表达式错误！')
        self.__join__.append('inner join {} on {}'.format(join_tablename, self._compile_on()))
        self.__join_on_exp__.clear()  # join
        return self

    def leftjoin_tuple(self, join_tablename, on):
        self.join_on_exp(on)
        if not self.__join_on_exp__:
            raise Exception('连表查询缺少__join_on_exp__参数表达式错误！')
        self.__join__.append('left join {} on {}'.format(join_tablename, self._compile_on()))
        self.__join_on_exp__.clear()  # join
        return self

    def rightjoin_tuple(self, join_tablename, on):
        self.join_on_exp(on)
        if not self.__join_on_exp__:
            raise Exception('连表查询缺少__join_on_exp__参数表达式错误！')
        self.__join__.append('right join {} on {}'.format(join_tablename, self._compile_on()))
        self.__join_on_exp__.clear()  # join
        return self

    def full_outer_join_tuple(self, join_tablename, on):
        self.join_on_exp(on)
        if not self.__join_on_exp__:
            raise Exception('连表查询缺少__join_on_exp__参数表达式错误！')
        self.__join__.append('full outer join {} on {}'.format(join_tablename, self._compile_on()))
        self.__join_on_exp__.clear()  # join
        return self
